﻿module Analyzer.D.syntax.declarations;
import Analyzer.D.syntax.CoreAnalyzer;

class Declaration : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        Declaration:
            Type Declarator ;
            Type Declarator , DeclIdentifierList ;
            Type Declarator Parameters ;
            Type Declarator Parameters FunctionBody
            AutoDeclaration        
     */
    public void parse()
    {
        if( AutoDeclaration.isAutoDeclaration(ts) )
        {
            parseR!(AutoDeclaration);
            return;
        }

		int prevType = globalDType;

		parseR!(Type);

		int lineNumber = ts.peek().lineNumber; // Kuan Hsu

		if( globalDType & D_TYPEOF )
		{
			parseR!( IdentifierSequence );
			globalDType = prevType;
			return;
		}
		
        parseR!(Declarator);
        if( ts.next( TOK.Semicolon ) )
        {
			if( globalDType & ( D_ALIAS | D_TYPEDEF ) )
				activeNode.addLeaf( globalProt, globalDType, globalIdentifier, globalTypeIdentifier, lineNumber ); // Kuan Hsu
			else
				activeNode.addLeaf( globalProt, D_VARIABLE, globalIdentifier, globalTypeIdentifier, lineNumber ); // Kuan Hsu
			
            parseTerminal();
        }
        else if( ts.next( TOK.Comma ) )
        {
			activeNode.addLeaf( globalProt, D_VARIABLE, globalIdentifier, globalTypeIdentifier, lineNumber ); // Kuan Hsu
			
            parseTerminal();
            parseR!(DeclIdentifierList);
            parseTerminal( TOK.Semicolon );
        }
        else
        {
			// Kuan Hsu
			int funProt = globalProt, funLN = lineNumber;
			char[] funIdent = globalIdentifier, funTypeIdent = globalTypeIdentifier;
			// activeNode = activeNode.addLeaf( globalProt, D_FUNCTION, globalIdentifier, globalTypeIdentifier, lineNumber );
			// End of Kuan Hsu
			
            parseR!(Parameters);

			bool bFunctionTemplateDeclaration = bFunctionTemplate; // Kuan Hsu
			activeNode = activeNode.addLeaf( funProt, D_FUNCTION, funIdent,funTypeIdent, lineNumber, globalParams ); // Kuan Hsu

			if( globalParams.length )
			{
				char[][] params;

				int 	countParen;
				char[]  string;
				
				foreach( char c; std.string.strip( globalParams ) )
				{
					string ~= c;
					
					switch( c )
					{
						case '(': countParen ++; break;
						case ')': countParen --; break;
						case ',':
							if( countParen == 0 )
							{
								params ~= string[0..length - 1];
								string = null;
							}
							
							break;
						default: break;
					}
				}

				if( string.length )	params ~= string;

				foreach( char[] s; params )
				{
					char[] paramString = std.string.strip( s );
					int spacePos = std.string.rfind( paramString, " " );
					if( spacePos > 0 )
						if( spacePos < paramString.length - 1 )
							activeNode.addLeaf( 0, D_PARAMETER, paramString[spacePos + 1..length], paramString[0..spacePos], lineNumber );
				}
			}
			
			//activeNode.parameterString = globalParams; // Kuan Hsu
			
			
            if( ts.next( TOK.Semicolon ) )
            {
                parseTerminal();
            }
            else
            {
				globalProt = 0;
                parseR!(FunctionBody);
            }

			// Kuan Hsu
			activeNode = activeNode.getRoot();
			if( bFunctionTemplateDeclaration ) activeNode = activeNode.getRoot();
			// End of Kuan Hsu
			
        }
    }
}

class Parameters : ParseRule
{
    public this(TokenScanner ts) { super(ts); }

    /**
        Parameters:
            TemplateParameters FunctionParameters
            FunctionParameters
     */

    public void parse()
    {
		globalParams = null; // Kuan Hsu
		
        expect( TOK.Openparen );
        auto cursor = ts.cursor();
        ts.skipParens();
        bool isTemplate = ts.next( TOK.Openparen ); // (...)(...)
        ts.setCursor( cursor );

        if( isTemplate )
        {
			// Kuan Hsu
			int lineNumber = ts.peek().lineNumber; 
			activeNode = activeNode.addLeaf( 0, D_TEMPLATE, globalIdentifier, null, lineNumber );
			// End of Kuan Hsu

            parseR!(TemplateParameters);

			// Kuan Hsu
			activeNode.parameterString = globalParams;
			bFunctionTemplate = true;
			// End of Kuan Hsu
			
            parseR!(FunctionParameters);
        }
        else
        {
			bFunctionTemplate = false; // Kuan Hsu
            parseR!(FunctionParameters);
        }
    }
}

class AutoDeclaration : ParseRule
{
    public this(TokenScanner ts)
    {
        super(ts);
    }

    /**
        AutoDeclaration:
            StorageClass Identifier = Expression ;
            StorageClass AutoDeclaration
     */
    public void parse()
    {
        while( StorageClass.isStorageClass(ts.peek().type) )
        {
            parseTerminal();
        }

		tokenText = null; // Kuan Hsu
        parseR!(Identifier);
		globalIdentifier = tokenText; // Kuan Hsu

        parseTerminal( TOK.Tassign );

        parseR!(Expression);

		activeNode.addLeaf( globalProt, D_VARIABLE, globalIdentifier, null, ts.peek().lineNumber ); // Kuan Hsu
		
        parseTerminal( TOK.Semicolon );
    }

    public static bool isAutoDeclaration(TokenScanner ts)
    {
        int originalPlace = ts.cursor;
        bool stc()
        {
            return StorageClass.isStorageClass(ts.peek().type);
        }
        scope(exit)
        {
            ts.setCursor(originalPlace);
        }

        if( !stc() ) return false;
        while( stc() )
        {
            ts.read();
        }
        if( !ts.next( TOK.Identifier ) )
        {
            return false;
        }
        ts.read();
        if( !ts.next( TOK.Tassign ) )
        {
            return false;
        }
        return true;
    }
}

class Type : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        Type:
            IdentifierSequence
            IdentifierSequence TypeSuffixes
            typeof
     */
    public void parse()
    {
		tokenText = null; // Kuan Hsu
		
        if( ts.next( TOK.Ttypeof ) )
        {
			parseR!(Typeof);

			if( ts.next( TOK.Openbracket ) ) 
				parseR!(TypeSuffixes); // Kuan Hsu
			else if( ts.next( TOK.Tdot ) )
			{
				globalDType = D_TYPEOF;
			}
		} 
		else 
		{ 
			parseR!(IdentifierSequence);
            if( isTypeSuffixStart( ts ) )
            {
                parseR!(TypeSuffixes);
            }
        }

		globalTypeIdentifier = tokenText; // Kuan Hsu
    }
}

/**
    returns whether or not this can be the start of a typesuffix
    *
    [
    function
    delegate
    
    but of course, not all '[' are type suffixes, so this is not perfect.
    use with care!
 */
bool isTypeSuffixStart( TokenScanner ts )
{
    return
    (
        ts.next( TOK.Tmul ) ||
        ts.next( TOK.Openbracket ) ||
        ts.next( TOK.Tfunction ) ||
        ts.next( TOK.Tdelegate )
    );
}

class TypeSuffixes : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        TypeSuffixes:
            TypeSuffix
            TypeSuffix TypeSuffixes
     */
    public void parse()
    {
        parseR!(TypeSuffix);
        if( isTypeSuffixStart( ts ) )
        {
            parseR!(TypeSuffixes);
        }
    }
}

class TypeSuffix : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        TypeSuffix:
            Pointer
            Array
            FunctionPointer
            Delegate
     */
    public void parse()
    {
        if( ts.next( TOK.Tmul ) )
        {
            parseR!(Pointer);
        }
        else if( ts.next( TOK.Openbracket ) )
        {
            //parseR!(Array);
			parseR!(ArrayIndex); // Kuan Hsu
        }
        else if( ts.next( TOK.Tfunction ) )
        {
            parseR!(FunctionPointer);
        }
        else
        {
            parseR!(Delegate);
        }
    }
}

class Pointer : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        Pointer:
            *
     */
    public void parse()
    {
        parseTerminal( TOK.Tmul );
    }
}

class Array : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        Array:
            []
            [ ExprType ]
     */
    public void parse()
    {
        parseTerminal( TOK.Openbracket );
        if( !ts.next( TOK.Closebracket ) )
        {
            parseR!(ExprType);
        }
        parseTerminal( TOK.Closebracket );
    }
}

class Typeof : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        Typeof:
            typeof ( Expression )
     */
    public void parse()
    {
        parseTerminal( TOK.Ttypeof );
        parseTerminal( TOK.Openparen );
        parseR!(Expression);
        parseTerminal( TOK.Closeparen );
    }
}

class ExprType : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        ExprType:
            AssignExpression
            AssignExpression TypeSuffixes
            Typeof
     */
    public void parse()
    {
        if( ts.next( TOK.Ttypeof ) )
        {
            parseR!(Typeof);
            return;
        }
        else
        {
            parseR!(AssignExpression);
            if( isTypeSuffixStart(ts) )
            {
                parseR!(TypeSuffixes);
            }
        }
    }
}

class FunctionPointer : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        FunctionPointer:
            function FunctionParameters
     */
    public void parse()
    {
		globalParams = null; // Kuan Hsu
		
        parseTerminal( TOK.Tfunction );

		// Kuan Hsu
		char[] typeIdent = tokenText;
		if( tokenText.length >= 8 )
			typeIdent = std.string.insert( tokenText, tokenText.length - 8, " " );
		// End of Kuan Hsu

        parseR!(FunctionParameters);

		// Kuan Hsu
		if( globalParams.length )
			if( globalParams[length - 1] == ' ' )  globalParams.length = globalParams.length - 1;
			
		tokenText = typeIdent ~ "(" ~ globalParams ~ ")";
		// End of Kuan Hsu
    }
}

class Delegate : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        Delegate:
            delegate FunctionParameters
     */
    public void parse()
    {
        parseTerminal( TOK.Tdelegate );

		// Kuan Hsu
		char[] typeIdent = tokenText;
		if( tokenText.length >= 8 )
			typeIdent = std.string.insert( tokenText, tokenText.length - 8, " " );
		// End of Kuan Hsu
		
        parseR!(FunctionParameters);

		// Kuan Hsu
		if( globalParams.length )
			if( globalParams[length - 1] == ' ' )  globalParams.length = globalParams.length - 1;
		
		tokenText = typeIdent ~ "(" ~ globalParams ~ ")";
		// End of Kuan Hsu
    }
}

bool isDeclaratorStart( TokenScanner ts )
{
    return (ts.next( TOK.Identifier ) || ts.next( TOK.Openparen ));
}

class Declarator : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        Declarator:
            Identifier
            Declarator CTypeSuffixes
            Declarator = Initializer
            ( Declarator )
            ( TypeSuffixes Declarator )
            ( TypeSuffixes )
     */
    public void parse()
    {
		tokenText = null; // Kuan Hsu
		
        if( ts.next( TOK.Identifier ) )
        {
            parseR!(Identifier);
        }
        else
        {
            parseTerminal( TOK.Openparen );
            if( isTypeSuffixStart( ts ) )
            {
                parseR!(TypeSuffixes);
                if( ts.next( TOK.Closeparen ) )
                {
                    parseTerminal();
                    return;
                }
            }
            parseR!(Declarator);
            parseTerminal( TOK.Closeparen );
        }

        if( ts.next( TOK.Openbracket ) )
        {
            parseR!(CTypeSuffixes);
        }

		globalIdentifier = tokenText; // Kuan Hsu

        if( ts.next( TOK.Tassign ) )
        {
            parseTerminal();
            parseR!(Initializer);
        }
    }
}

class DeclIdentifierList : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        DeclIdentifierList:
            DeclIdentifier
            DeclIdentifier, DeclIdentifierList
     */
    public void parse()
    {
        parseR!(DeclIdentifier);
		activeNode.addLeaf( globalProt, D_VARIABLE, globalIdentifier, globalTypeIdentifier, ts.peek().lineNumber ); // Kuan Hsu
        if( ts.next( TOK.Comma ) )
        {
            parseTerminal();
            parse();
        }
    }
}

class DeclIdentifier : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        DeclIdentifier:
            Identifier
            Identifier = Initializer
     */
    public void parse()
    {
		tokenText = null;
        parseR!(Identifier);
		globalIdentifier = tokenText;
        if( ts.next( TOK.Tassign ) )
        {
            parseTerminal();
            parseR!(Initializer);
        }
    }
}

class CTypeSuffixes : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        CTypeSuffixes:
            Array
            Array CTypeSuffixes    
     */
    public void parse()
    {
        parseR!(Array);
        if( ts.next( TOK.Openbracket ) )
        {
            parseR!(CTypeSuffixes);
        }
    }
}

class FunctionParameters : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        FunctionParameters:
            ( )
            ( FunctionParameterList )
     */
    public void parse()
    {
		globalParams = null; // Kuan Hsu
        parseTerminal( TOK.Openparen );

        if( !ts.next( TOK.Closeparen ) )
        {
            parseR!(FunctionParameterList);
        }
        parseTerminal( TOK.Closeparen );
    }
}

class FunctionParameterList : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        FunctionParameterList:
            Paremeter
            FunctionParameter, FunctionParameterList
            FunctionParameter ...
            ...
     */
    public void parse()
    {
        if( ts.next( TOK.Tdotdotdot ) )
        {
            parseTerminal();
			globalParams ~= "..."; // Kuan Hsu
            return;
        }
        
        parseR!(FunctionParameter);
        if( ts.next( TOK.Tdotdotdot ) )
        {
            parseTerminal();
			globalParams ~= "..."; // Kuan Hsu
            return;
        }
        if( ts.next( TOK.Comma ) )
        {
            parseTerminal();
			globalParams ~= ", "; // Kuan Hsu
            parse();
        }
    }
}

class FunctionParameter : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        FunctionParameter:
            Type
            Type Declarator
            Type Declarator FunctionParameters             
            Type Declarator = Initializer
            InOut FunctionParameter
     */
    public void parse()
    {
        if( nextinout(ts) )
        {
            parseR!(InOut);
        }

		char[] prevParamText = globalParams; // Kuan Hsu
        parseR!(Type);
		globalParams = prevParamText ~ globalTypeIdentifier ~ " "; // Kuan Hsu
		
        if( isDeclaratorStart( ts ) )
        {
            parseR!(Declarator);

			globalParams ~= globalIdentifier; // Kuan Hsu

			
            if( ts.next( TOK.Tassign ) )
            {
                parseTerminal();
                parseR!(Initializer);
            }
            else if( ts.next( TOK.Openparen ) )
            {
                parseR!(FunctionParameters);
            }
        }

		/*
		// Kuan Hsu
		if( activeNode.DType & D_FUNCTION )
			activeNode.addLeaf( 0, D_PARAMETER, globalIdentifier, globalTypeIdentifier, ts.peek().lineNumber );
		// End of Kuan Hsu
		*/
    }
}

class InOut : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        InOut:
            in
            out
            inout
			ref
            lazy
     */
    public void parse()
    {
        if( nextinout(ts) )
        {
			tokenText = null; //Kuan Hsu
            parseTerminal();
			globalParams ~= ( tokenText ~ " " );
        }
        else
        {
            throw new ParserException( ts, "Expecting in/out/ref/lazy" );
        }
    }
}

bool nextinout(TokenScanner ts)
{
    switch( ts.peek().type )
    {
        case    
            TOK.Tin,
            TOK.Tout, 
            TOK.Tinout,
			TOK.Tref,
            TOK.Tlazy: 
                return true;
        default: 
                return false;
    }
}

class FunctionBody : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        FunctionBody:
            StatementBlock
            body StatementBlock
            FunctionContracts body StatementBlock
     */
    public void parse()
    {
        if( ts.next( TOK.Tin ) || ts.next( TOK.Tout ) )
        {
            parseR!(FunctionContracts);
            parseTerminal( TOK.Tbody );
        }
        else if( ts.next( TOK.Tbody ) )
        {
            parseTerminal();
        }
        parseR!(StatementBlock);
    }
}

class FunctionContracts : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        FunctionContracts:
            InContract
            OutContract
            InContract OutContract
            OutContract InContract
     */
    public void parse()
    {
        bool incon = false;
        if( ts.next( TOK.Tin ) )
        {
            incon = true;
            parseR!(InContract);
        }
        if( ts.next( TOK.Tout ) )
        {
            parseR!(OutContract);
        }
        if( !incon )
        {
            if( ts.next( TOK.Tin ) )
            {
                incon = true;
                parseR!(InContract);
            }
        }
    }
}

class InContract : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        InContract:
            in StatementBlock
     */
    public void parse()
    {
        parseTerminal( TOK.Tin );
        parseR!(StatementBlock);
    }
}

class OutContract : ParseRule
{
    this(TokenScanner ts)
    {
        super(ts);
    }
    /**
        OutContract:
            out StatementBlock
            out ( Identifier ) StatementBlock
     */
    public void parse()
    {
        parseTerminal( TOK.Tout );
        if( ts.next( TOK.Openparen ) )
        {
            parseTerminal();
            parseR!(Identifier);
            parseTerminal( TOK.Closeparen );
        }
        parseR!(StatementBlock);
    }
}

class Constructor : ParseRule
{
    public this(TokenScanner ts)
    {
        super(ts);
    }

    /**
        Constructor:
            this FunctionParameters FunctionBody
            this FunctionParameters ;
     */
    public void parse()
    {
        parseTerminal( TOK.Tthis );

		activeNode = activeNode.addLeaf( globalProt, D_CTOR, "this", null, ts.peek().lineNumber ); // Kuan Hsu

        parseR!(FunctionParameters);

		activeNode.parameterString = globalParams; // Kuan Hsu

        if( ts.next( TOK.Semicolon ) )
        {
            parseTerminal();
        }
        else
        {
			globalProt = 0;
            parseR!(FunctionBody);
        }

		activeNode = activeNode.getRoot(); // Kuan Hsu
    }
}

class Destructor : ParseRule
{
    public this(TokenScanner ts)
    {
        super(ts);
    }

    /**
        Destructor:
            ~ this ( ) FunctionBody
            ~ this ( ) ;
     */
    public void parse()
    {
        parseTerminal( TOK.Ttilde );
        parseTerminal( TOK.Tthis );

		activeNode = activeNode.addLeaf( globalProt, D_DTOR, "~this", null, ts.peek().lineNumber ); // Kuan Hsu
		
        parseTerminal( TOK.Openparen );
        parseTerminal( TOK.Closeparen );
        if( ts.next( TOK.Semicolon ) )
        {
            parseTerminal();
        }
        else
        {
			globalProt = 0;
            parseR!(FunctionBody);
        }

		activeNode = activeNode.getRoot(); // Kuan Hsu
    }
}

class Allocator : ParseRule
{
    public this(TokenScanner ts)
    {
        super(ts);
    }

    /**
        Allocator:
            new FunctionParameters FunctionBody
            new FunctionParameters ;
     */
    public void parse()
    {
        parseTerminal( TOK.Tnew );
        parseR!(FunctionParameters);
        if( ts.next( TOK.Semicolon ) )
        {
            parseTerminal();
        }
        else
        {
            parseR!(FunctionBody);
        }
    }
}

class Dellocator : ParseRule
{
    public this(TokenScanner ts)
    {
        super(ts);
    }

    /**
        Dellocator:
            delete FunctionParameters FunctionBody
            delete FunctionParameters ;
     */
    public void parse()
    {
        parseTerminal( TOK.Tdelete );
        parseR!(FunctionParameters);
        if( ts.next( TOK.Semicolon ) )
        {
            parseTerminal();
        }
        else
        {
            parseR!(FunctionBody);
        }
    }
}